#!/usr/bin/env python
# -*- coding: utf8 -*-
# title       :
# description :
# author      :'ShenMeng'


import os
import socket
import yaml
import time
import datetime
import abc


class BatchBase(object):
    def __init__(self, batchType, rootPath, sub=None, id=None):
        self._batchType = batchType
        self.rootPath = rootPath
        self.dataRoot = os.path.join(self.rootPath, '.data.', '{}'.format(self._batchType))
        if id:
            self.id = id
        else:
            self.id = socket.gethostname()
        self._sub = sub
        if not os.path.isdir(self.dataRoot):
            os.makedirs(self.dataRoot)
        self.taskDataRoot = os.path.join(self.dataRoot, str(self.id))
        if not os.path.isdir(self.taskDataRoot):
            os.makedirs(self.taskDataRoot)
        #
        if isinstance(self._sub, str) and self._sub != 'all':
            if not os.path.isdir(os.path.join(self.dataRoot, self._sub)):
                os.makedirs(os.path.join(self.dataRoot, self._sub))
            if not os.path.isdir(os.path.join(self.taskDataRoot, self._sub)):
                os.makedirs(os.path.join(self.taskDataRoot, self._sub))
                
            self.errorDataFile = os.path.join(self.dataRoot, self._sub, 'error.data')
            self._errorLockFile = os.path.join(self.dataRoot, self._sub, 'error.lock')
            self.okDataFile = os.path.join(self.dataRoot, self._sub, 'ok.data')
            self._okLockFile = os.path.join(self.dataRoot, self._sub, 'ok.lock')
            self.assignDataFile = os.path.join(self.dataRoot, self._sub, 'assign.data')
            self._assignLockFile = os.path.join(self.dataRoot, self._sub, 'assign.lock')

            self.taskErrorDataFile = os.path.join(self.taskDataRoot, self._sub, 'error.data')
            self.taskOkDataFile = os.path.join(self.taskDataRoot, self._sub, 'ok.data')
            self.taskAssignDataFile = os.path.join(self.taskDataRoot, self._sub, 'assign.data')
        else:
            self.errorDataFile = os.path.join(self.dataRoot, 'error.data')
            self._errorLockFile = os.path.join(self.dataRoot, 'error.lock')
            self.okDataFile = os.path.join(self.dataRoot, 'ok.data')
            self._okLockFile = os.path.join(self.dataRoot, 'ok.lock')
            self.assignDataFile = os.path.join(self.dataRoot, 'assign.data')
            self._assignLockFile = os.path.join(self.dataRoot, 'assign.lock') 
            
            self.taskErrorDataFile = os.path.join(self.taskDataRoot, 'error.data')
            self.taskOkDataFile = os.path.join(self.taskDataRoot, 'ok.data')
            self.taskAssignDataFile = os.path.join(self.taskDataRoot, 'assign.data')
    @property
    def errorData(self):
        if not os.path.isfile(self.errorDataFile):
            return None
        return self.read(self.errorDataFile)
        
    @property
    def errorUser(self):
        if not os.path.isfile(self._errorLockFile):
            return None
        return self.read(self._errorLockFile) 
        
    @property
    def okData(self):
        if not os.path.isfile(self.okDataFile):
            return None
        return self.read(self.okDataFile) 
        
    @property
    def okUser(self):
        if not os.path.isfile(self._okLockFile):
            return None
        return self.read(self._okLockFile) 
        
    @property
    def assignData(self):
        if not os.path.isfile(self.assignDataFile):
            return None
        return self.read(self.assignDataFile) 
        
    @property
    def assignUser(self):
        if not os.path.isfile(self._assignLockFile):
            return None
        return self.read(self._assignLockFile) 
            
    @property
    def isErrorDataLock(self):
        if os.path.isfile(self._errorLockFile):
            return True
        return False
        
    @property
    def isOkDataLock(self):
        if os.path.isfile(self._okLockFile):
            return True
        return False
        
    @property
    def isAssignDataLock(self):
        if os.path.isfile(self._assignLockFile):
            return True
        
        return False
        
    @property
    def taskErrorData(self):
        if not os.path.isfile(self.taskErrorDataFile):
            return None
        return self.read(self.taskErrorDataFile)
    
    @property
    def taskOkData(self):
        if not os.path.isfile(self.taskOkDataFile):
            return None
        return self.read(self.taskOkDataFile)  
        
    @property
    def taskAssignData(self):
        if not os.path.isfile(self.taskAssignDataFile):
            return None
        return self.read(self.taskAssignDataFile) 
        
    @staticmethod
    def read(filePath):
        data = None
        with open(filePath) as f:
            data = yaml.load(f)
        return data
        
    @staticmethod
    def write(data, filePath, status='a', unicode=False):
        with open(filePath, status) as f:
            if data:
                yaml.safe_dump(data, f, default_flow_style=False, allow_unicode=unicode)
            
    def setLock(self, filePath, status=0, data='' ):
        if status:
            if os.path.isfile(filePath):
                raise ValueError("")
            else:
                self.write(data, filePath)
        else:
            if not os.path.isfile(filePath):
                raise ValueError("")
            else:
                os.remove(filePath)
    @staticmethod
    def getTime():
        data = datetime.datetime.fromtimestamp(time.time())
        return data.strftime('%Y-%m-%d|%H.%M.%S')
        
    @abc.abstractmethod
    def setAssignDataLock(self):
        raise NotImplementedError
        
class BatchManager(BatchBase):
    def __init__(self, batchType, rootPath, sub=None, id=None):
        super(BatchManager, self).__init__(batchType, rootPath, sub, id=id)
        
    def updateAssignData(self, data, status='a'):
        self.write(data, self.assignDataFile, status=status)

    def updateErrorData(self, data, status='a'):
        self.write(data, self.errorDataFile, status=status)
 
    def updateOkData(self, data, status='a'):
        self.write(data, self.okDataFile, status=status)
  
    def updateTaskErrorData(self, data, status='a'):
        self.write(data, self.taskErrorDataFile, status=status)
        
    def updateTaskOkData(self, data, status='a'):
        self.write(data, self.taskOkDataFile, status=status)
        
    def updateTaskAssignData(self, data, status='a'):
        self.write(data, self.taskAssignDataFile, status=status)
        
    def setAssignDataLock(self, status):
        self.setLock(self._assignLockFile, status, self.id)
        
    def setErrorDataLock(self, status):
        self.setLock(self._errorLockFile, status, self.id)
        
    def setOkDataLock(self, status):
        self.setLock(self._okLockFile, status, self.id)
        
class Tasker(BatchBase):
    def __init__(self, batchType, rootPath, sub=None, timeout=300):
        super(Tasker, self).__init__(batchType, rootPath, sub)
        self.timeout = timeout

    def loggle(self, data, status, unicode=False):
        if status == 'error':
            dataFile = 'self.errorDataFile'
            takdDataFile = 'self.taskErrorDataFile'
            isLock = 'self.isErrorDataLock'
            setLock = 'self.setErrorDataLock'
            lockFile = 'self._errorLockFile'
        elif status == 'ok':
            dataFile = 'self.okDataFile'
            takdDataFile = 'self.taskOkDataFile'
            isLock = 'self.isOkDataLock'
            setLock = 'self.setOkDataLock'
            lockFile = 'self._okLockFile'
        eval("self.write({data}, {dataFile}, unicode={unicode})".format(data=data, dataFile=takdDataFile, unicode=unicode))
        startTime = time.time()
        while True:
            if not eval("%s" % isLock):
                try:
                    eval('%s(1, "%s")' % (setLock, self.id))
                    eval("self.write({data}, {dataFile}, unicode={unicode})".format(data=data, dataFile=dataFile, unicode=unicode))
                except Exception, e:
                    print e
                finally:
                    eval('%s(0, "%s")' % (setLock, self.id))
                return
            endTime = time.time()
            if endTime-startTime > self.timeout:
                print 'time out!'
                return
    
    def setErrorDataLock(self, status, data):
        self.setLock(self._errorLockFile, status, data)
        
    def setOkDataLock(self, status, data):
        self.setLock(self._okLockFile, status, data)
        
    def setAssignDataLock(self, status, data):
        self.setLock(self._assignLockFile, status, data)






